package info.liuxing.httpclient;

import info.liuxing.okhttp.ssl.TrustAllManager;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.*;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.concurrent.TimeUnit;

/**
 * HttpClientUtil
 *
 * @author liuxing (SE)
 * @summary HttpClientUtil
 * @Copyright (c) 2017, Lianjia Group All Rights Reserved.
 * @since 2017-12-01 14:43
 */
public class HttpClientUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpClientUtil.class);

    private static CloseableHttpClient httpClient;

    static {
        HttpClientBuilder builder = HttpClients.custom();
        builder.setConnectionTimeToLive(30L, TimeUnit.SECONDS);
        builder.setMaxConnTotal(1000);
        builder.setMaxConnPerRoute(1000);

        builder.setRetryHandler(new DefaultHttpRequestRetryHandler(2, true));

        // 保持长连接配置，需要在头添加Keep-Alive
        // 该策略依赖响应头的Keep-Alive参数：如 Keep-Alive: timeout=5, max=100 单位秒
        // 否则则依赖ConnectionTimeToLive的设置
        builder.setKeepAliveStrategy(DefaultConnectionKeepAliveStrategy.INSTANCE);

//        List<Header> headers = new ArrayList<>();
//        headers.add(new BasicHeader(HTTP.USER_AGENT, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
//        headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6"));
//        headers.add(new BasicHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_KEEP_ALIVE));
//
//        builder.setDefaultHeaders(headers);

        try {
            SSLContext sslContext = SSLContexts.custom().loadTrustMaterial(null, (TrustStrategy) (chain, authType) -> true).build();
            builder.setSSLContext(sslContext);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, new TrustManager[]{new TrustAllManager()}, new SecureRandom());
            builder.setSSLContext(sc);
        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
        }

        RequestConfig requestConfig = RequestConfig.custom()
                // 读写超时
                .setSocketTimeout(10000)
                // 请求超时
                .setConnectTimeout(10000)
                // 从连接池中获取连接的时间，非请求时间
                .setConnectionRequestTimeout(200)
                // 最大重定向次数
                .setMaxRedirects(10)
                // 自动gzip
                .setContentCompressionEnabled(true)
                .build();

        builder.setDefaultRequestConfig(requestConfig);

        httpClient = builder.build();

        LOGGER.info("requestConfig: {}", requestConfig.toString());
    }

    public static CloseableHttpClient client() {
        return httpClient;
    }

    /**
     * 简单的get请求
     *
     * @param url
     * @return
     */
    public static String doGet(String url) {
        HttpGet httpGet = new HttpGet(url);
        try {
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                LOGGER.debug("response status: {}", response.getStatusLine());
                return EntityUtils.toString(response.getEntity());
            }
        } catch (ClientProtocolException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            httpGet.releaseConnection();
        }

        return null;
    }

    /**
     * 上传文件
     *
     * @param url
     * @param filePath
     * @return
     */
    public static String upload(String url, String filePath) {
        HttpPost httpPost = new HttpPost(url);

        try {
            File file = new File(filePath);

            InputStreamEntity reqEntity = new InputStreamEntity(new FileInputStream(file), -1, ContentType.APPLICATION_OCTET_STREAM);
            reqEntity.setChunked(true);

            httpPost.setEntity(reqEntity);

            LOGGER.debug("Executing request: {}", httpPost.getRequestLine());
            try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
                LOGGER.debug("response status: {}", response.getStatusLine());
                return EntityUtils.toString(response.getEntity());
            }
        } catch (FileNotFoundException e) {
            LOGGER.error(e.getMessage(), e);
        } catch (IOException e) {
            LOGGER.error(e.getMessage(), e);
        } finally {
            httpPost.releaseConnection();
        }

        return null;
    }
}


